/*
* Copyright (c) 2015 Daimler AG / Moovel GmbH
*
* All rights reserved
*/
package com.car2go.maps.google.adapter;
import android.support.annotation.NonNull;
import com.car2go.maps.google.adapter.factory.Mapper;
import com.car2go.maps.google.adapter.factory.anymap.CameraPositionMapper;
import com.car2go.maps.google.adapter.factory.anymap.CircleMapper;
import com.car2go.maps.google.adapter.factory.anymap.LatLngBoundsMapper;
import com.car2go.maps.google.adapter.factory.anymap.LatLngMapper;
import com.car2go.maps.google.adapter.factory.anymap.MarkerMapper;
import com.car2go.maps.google.adapter.factory.anymap.PolygonMapper;
import com.car2go.maps.google.adapter.factory.anymap.PolylineMapper;
import com.car2go.maps.google.adapter.factory.anymap.ProjectionMapper;
import com.car2go.maps.google.adapter.factory.anymap.UiSettingsMapper;
import com.car2go.maps.google.adapter.factory.anymap.VisibleRegionMapper;
import com.car2go.maps.google.adapter.factory.google.CircleOptionsMapper;
import com.car2go.maps.google.adapter.factory.google.MarkerOptionsMapper;
import com.car2go.maps.google.adapter.factory.google.PolygonOptionsMapper;
import com.car2go.maps.google.adapter.factory.google.PolylineOptionsMapper;
import com.car2go.maps.model.CircleOptions;
import com.car2go.maps.model.MarkerOptions;
import com.car2go.maps.model.PolygonOptions;
import com.car2go.maps.model.PolylineOptions;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.VisibleRegion;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Utility for adapting Google entities to AnyMap and vice versa.
*/
public class AnyMapAdapter {
private static final AnyMapAdapter INSTANCE = new AnyMapAdapter();
private final HashMap<Class<?>, Mapper> mappers = new HashMap<>();
AnyMapAdapter() {
registerGoogleToAnyMapMappers();
registerAnyMapToGoogleMappers();
}
/**
* @return instance of {@link AnyMapAdapter}
*/
private static AnyMapAdapter getInstance() {
return INSTANCE;
}
/**
* Adapts input object to it's respective alternative. That is, adapts Google entities to
* AnyMap entities and vice versa. If input is {@code null}, outputs {@code null}.
*
* @param object object to adapt
* @return adapted object
*/
public static <I, O> O adapt(I object) {
return getInstance().map(object);
}
/**
* Convenience for {@link #adapt(Object)} which works on a {@link List} of objects.
*
* @param type type of input objects being adapted
* @param list list of objects being adapted
* @return list of adapted objects
*/
public static <I, O> List<O> adaptList(Class<? extends I> type, List<I> list) {
return getInstance().mapList(type, list);
}
private void registerGoogleToAnyMapMappers() {
registerMapper(
LatLng.class,
new LatLngMapper()
);
registerMapper(
LatLngBounds.class,
new LatLngBoundsMapper()
);
registerMapper(
CameraPosition.class,
new CameraPositionMapper()
);
registerMapper(
Projection.class,
new ProjectionMapper()
);
registerMapper(
VisibleRegion.class,
new VisibleRegionMapper()
);
registerMapper(
UiSettings.class,
new UiSettingsMapper()
);
registerMapper(
Marker.class,
new MarkerMapper()
);
registerMapper(
Circle.class,
new CircleMapper()
);
registerMapper(
Polygon.class,
new PolygonMapper()
);
registerMapper(
Polyline.class,
new PolylineMapper()
);
}
private void registerAnyMapToGoogleMappers() {
registerMapper(
com.car2go.maps.model.LatLng.class,
new com.car2go.maps.google.adapter.factory.google.LatLngMapper()
);
registerMapper(
com.car2go.maps.model.LatLngBounds.class,
new com.car2go.maps.google.adapter.factory.google.LatLngBoundsMapper()
);
registerMapper(
MarkerOptions.class,
new MarkerOptionsMapper()
);
registerMapper(
CircleOptions.class,
new CircleOptionsMapper()
);
registerMapper(
PolygonOptions.class,
new PolygonOptionsMapper()
);
registerMapper(
PolylineOptions.class,
new PolylineOptionsMapper()
);
}
/**
* Registers mapper which will map instances of input classes into some other type. Output
* type is defined by mapper.
*/
public <I> void registerMapper(Class<? extends I> inputClass, Mapper<I, ?> mapper) {
if (mappers.containsKey(inputClass)) {
throw new IllegalStateException(
"Mapper for class " + inputClass
+ " was already registered: " + mappers.get(inputClass)
);
}
mappers.put(inputClass, mapper);
}
/**
* Adapts input object to it's respective alternative. That is, adapts Google entities to
* AnyMap entities and vice versa. If input is {@code null}, outputs {@code null}.
*
* @param object object to adapt
* @return adapted object
*/
public <I, O> O map(I object) {
if (object == null) {
return null;
}
Mapper<I, O> mapper = findMapper(object.getClass());
return mapper.map(object);
}
/**
* Convenience for {@link #map(Object)} which works on a {@link List} of objects.
*
* @param type type of input objects being adapted
* @param input list of objects being adapted
* @return list of adapted objects
*/
public <I, O> List<O> mapList(Class<? extends I> type, List<I> input) {
Mapper<I, O> mapper = findMapper(type);
List<O> result = new ArrayList<>(input.size());
for (I inputItem : input) {
result.add(
mapper.map(inputItem)
);
}
return result;
}
@SuppressWarnings("unchecked")
@NonNull
private <I, O> Mapper<I, O> findMapper(Class<?> type) {
// We have to do unchecked cast since we don't know the exact type of adapter in our map
Mapper<I, O> mapper = mappers.get(type);
if (mapper == null) {
throw new IllegalStateException("No mapper for " + type);
}
return mapper;
}
}